#include <QApplication>
#include <QColor>
#include <QMouseEvent>
#include <QPainter>

#include "PannerWidget.h"

PannerWidget::PannerWidget(QWidget *parent, const QSize& viewportSize) :
    QWidget(parent), m_viewportSize(viewportSize), m_zoom(1.0)
{
    setCursor(Qt::OpenHandCursor);
}

double PannerWidget::aspectRatio(int sourceWidth, int destWidth, int sourceHeight, int destHeight)
{
    // source is image, widget is dest.
    if (sourceWidth > sourceHeight)
        return (double)destWidth / (double)sourceWidth;
    else
        return (double)destHeight / (double)sourceHeight;
}


void PannerWidget::mouseMoveEvent(QMouseEvent *event)
{
    // TODO: Need to prevent rect from moving outwith this widget.

    if ((event->buttons() & Qt::LeftButton) && m_insideRect)
    {
        updateLocation(event->pos());
    }
}

void PannerWidget::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        m_prevPosition.setX(m_rectangle.x() - event->pos().x());
        m_prevPosition.setY(m_rectangle.y() - event->pos().y());

        if (m_rectangle.contains(event->pos()))
        {
            m_insideRect = true;
            QApplication::setOverrideCursor(Qt::ClosedHandCursor);
            updateLocation(event->pos());
        }
        else
        {
            m_insideRect = false;
        }
     }
}

void PannerWidget::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        if (m_rectangle.contains(event->pos()))
        {
            updateLocation(event->pos());
        }

        m_insideRect = false;
        QApplication::restoreOverrideCursor();
    }
}

void PannerWidget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);

    painter.scale(m_imageScaleRatio, m_imageScaleRatio);
    painter.drawImage(0, 0, m_image);

    painter.resetTransform();

    painter.setPen(Qt::red);
    painter.drawRect(m_rectangle);

    QWidget::paintEvent(event);
}

void PannerWidget::resizeEvent(QResizeEvent* /*event*/)
{
    scaleImage();
    setRectangleSize();
    update();
}

void PannerWidget::setImage(const QImage &image)
{
    QRect rectangle;

    m_image = image;
    scaleImage();
    setRectangleSize();
    update();
}

void PannerWidget::scaleImage()
{
    // This gives the scale factor for the image such that it fits into the available
    // space and maintains the correct aspect ratio.
    m_imageScaleRatio = aspectRatio(m_image.width(), width(), m_image.height(), height());
}

void PannerWidget::setRectangleSize()
{
    double myZoom = 1.0 / m_zoom;

    m_rectangle.setWidth((m_viewportSize.width() * m_imageScaleRatio * myZoom) - 1);
    m_rectangle.setHeight((m_viewportSize.height() * m_imageScaleRatio * myZoom) - 1);

    double reciprocalRatio = 1.0 / m_imageScaleRatio;
    QRect rectangle;

    rectangle.setX(m_rectangle.x() * reciprocalRatio);
    rectangle.setY(m_rectangle.y() * reciprocalRatio);
    rectangle.setWidth((m_rectangle.width() * reciprocalRatio) - 1);
    rectangle.setHeight((m_rectangle.height() * reciprocalRatio) - 1);

    emit signalRectangleChanged(rectangle);
}

void PannerWidget::setZoom(double zoom)
{
    m_zoom = zoom;
    setRectangleSize();
    update();
}

void PannerWidget::slotSizeChanged(const QSize& size)
{
    if (!m_image.isNull())
    {
        m_viewportSize = size;
        setRectangleSize();

        update();
    }
}

void PannerWidget::updateLocation(const QPoint& pos)
{
    m_rectangle.moveTo(m_prevPosition.x() + pos.x(), m_prevPosition.y() + pos.y());
    update();

    double reciprocalRatio = 1.0 / m_imageScaleRatio;
    QRect rectangle;

    rectangle.setX(m_rectangle.x() * reciprocalRatio);
    rectangle.setY(m_rectangle.y() * reciprocalRatio);
    rectangle.setWidth((m_rectangle.width() * reciprocalRatio) - 1);
    rectangle.setHeight((m_rectangle.height() * reciprocalRatio) - 1);

    emit signalRectangleChanged(rectangle);
}
